Kanekonkon commited on
Commit
ed9ec98
·
verified ·
1 Parent(s): 149e2dd

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ checklist/c_code_review_checklist.pdf filter=lfs diff=lfs merge=lfs -text
37
+ checklist/coding_rule.pdf filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,12 +1,6 @@
1
  ---
2
- title: Hf MultiLLM
3
- emoji: 🚀
4
- colorFrom: gray
5
- colorTo: yellow
6
  sdk: gradio
7
  sdk_version: 5.49.1
8
- app_file: app.py
9
- pinned: false
10
  ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: hf_multiLLM
3
+ app_file: app.py
 
 
4
  sdk: gradio
5
  sdk_version: 5.49.1
 
 
6
  ---
 
 
app.py ADDED
@@ -0,0 +1,392 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ from pypdf import PdfReader
4
+ from sentence_transformers import SentenceTransformer
5
+ import chromadb
6
+ from chromadb.utils import embedding_functions
7
+ import ollama # Ollamaライブラリをインポート
8
+ from langchain_text_splitters import RecursiveCharacterTextSplitter
9
+ import uuid # For generating unique IDs for chunks
10
+ from dotenv import load_dotenv
11
+ # from pdfminer.high_level import extract_text as pdfminer_extract_text
12
+
13
+
14
+ # LLMクライアントのインポート
15
+ from openai import OpenAI
16
+ import anthropic
17
+ import google.generativeai as genai
18
+
19
+ # .envファイルから環境変数を読み込む
20
+ load_dotenv()
21
+
22
+ # --- APIキーの取得 ---
23
+ OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
24
+ ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY")
25
+ GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
26
+
27
+ # --- Ollamaクライアントの初期化 ---
28
+ client_ollama = ollama.Client()
29
+
30
+ OLLAMA_MODEL_NAME = "llama3.2"
31
+ # OLLAMA_MODEL_NAME = "llama3:8b-instruct-q4_0"
32
+
33
+
34
+ client_openai = None
35
+ OPENAI_MODEL_NAME = "gpt-4o-mini"
36
+ if OPENAI_API_KEY:
37
+ try:
38
+ client_openai = OpenAI(api_key=OPENAI_API_KEY)
39
+ print(f"OpenAIクライアントを初期化しました (モデル: {OPENAI_MODEL_NAME})。")
40
+ except Exception as e:
41
+ print(f"OpenAIクライアントの初期化に失敗しました: {e}")
42
+ client_openai = None
43
+ else:
44
+ print("OPENAI_API_KEYが設定されていません。OpenAIモデルは利用できません。")
45
+
46
+ client_anthropic = None
47
+ ANTHROPIC_MODEL_NAME = "claude-3-haiku-20240307"
48
+ if ANTHROPIC_API_KEY:
49
+ try:
50
+ client_anthropic = anthropic.Anthropic(api_key=ANTHROPIC_API_KEY)
51
+ print(f"Anthropicクライアントを初期化しました (モデル: {ANTHROPIC_MODEL_NAME})。")
52
+ except Exception as e:
53
+ print(f"Anthropicクライアントの初期化に失敗しました: {e}")
54
+ client_anthropic = None
55
+ else:
56
+ print("ANTHROPIC_API_KEYが設定されていません。Anthropicモデルは利用できません。")
57
+
58
+ client_gemini = None
59
+ GOOGLE_MODEL_NAME = "gemini-2.5-flash"
60
+ if GOOGLE_API_KEY:
61
+ try:
62
+ genai.configure(api_key=GOOGLE_API_KEY)
63
+ client_gemini = genai.GenerativeModel(GOOGLE_MODEL_NAME)
64
+ print(f"Google Geminiクライアントを初期化しました (モデル: {GOOGLE_MODEL_NAME})。")
65
+ except Exception as e:
66
+ print(f"Google Geminiクライアントの初期化に失敗しました: {e}")
67
+ client_gemini = None
68
+ else:
69
+ print("GOOGLE_API_KEYが設定されていません。Google Geminiモデルは利用できません。")
70
+
71
+ # --- 埋め込みモデルの初期化 ---
72
+ # 重複定義を削除し、1回のみ初期化
73
+ embedding_model = SentenceTransformer('pkshatech/GLuCoSE-base-ja') # 日本語対応の埋め込みモデル
74
+
75
+ # --- ChromaDBのカスタム埋め込み関数 ---
76
+ # 重複定義を削除し、1回のみ定義
77
+ class SBERTEmbeddingFunction(embedding_functions.EmbeddingFunction):
78
+ def __init__(self, model):
79
+ self.model = model
80
+ def __call__(self, texts):
81
+ # sentence-transformersモデルはnumpy配列を返すため、tolist()でPythonリストに変換
82
+ return self.model.encode(texts).tolist()
83
+
84
+ sbert_ef = SBERTEmbeddingFunction(embedding_model)
85
+
86
+ # --- ChromaDBクライアントとコレクションの初期化 ---
87
+ # インメモリモードで動作させ、アプリケーション起動時にコレクションをリセットします。
88
+ # グローバル変数としてクライアントを保持
89
+ client = chromadb.Client()
90
+ collection_name = "pdf_documents_collection"
91
+
92
+ # アプリケーション起動時にコレクションが存在すれば削除し、新しく作成する
93
+ # (インメモリDBはセッションごとにリセットされるため、これは初回起動時のみ意味を持つ)
94
+ try:
95
+ client.delete_collection(name=collection_name)
96
+ print(f"既存のChromaDBコレクション '{collection_name}' を削除しました。")
97
+ except Exception as e:
98
+ # コレクションが存在しない場合はエラーになるので無視。デバッグ用にメッセージは出力。
99
+ print(f"ChromaDBコレクション '{collection_name}' の削除に失敗しました (存在しないか、その他のエラー): {e}")
100
+ pass
101
+
102
+ collection = client.get_or_create_collection(name=collection_name, embedding_function=sbert_ef)
103
+ print(f"ChromaDBコレクション '{collection_name}' を初期化しました。")
104
+
105
+ text_splitter = RecursiveCharacterTextSplitter(
106
+ chunk_size=1000, # チャンクの最大文字数
107
+ chunk_overlap=150, # チャンク間のオーバーラップ文字数
108
+ length_function=len, # 文字数で長さを計算
109
+ separators=["\n\n", "\n", " ", ""] # 分割の優先順位
110
+ )
111
+
112
+ # --- ヘルパー関数 ---
113
+ def extract_text_from_pdf(pdf_file_path):
114
+ """PDFファイルからテキストを抽出する"""
115
+ print(f"Attempting to extract text from: {pdf_file_path}")
116
+ try:
117
+ reader = PdfReader(pdf_file_path)
118
+ text = ""
119
+ if not reader.pages:
120
+ print(f" PDF '{os.path.basename(pdf_file_path)}' contains no pages.")
121
+ return "ERROR: PDFにページが含まれていません。" # プレフィックスを追加
122
+
123
+ for i, page in enumerate(reader.pages):
124
+ page_text = page.extract_text()
125
+ if page_text:
126
+ text += page_text + "\n"
127
+ print(f" Page {i+1} extracted text (first 100 chars): {page_text[:100].replace('\n', ' ')}...")
128
+ else:
129
+ print(f" Page {i+1} extracted no text.")
130
+
131
+ if not text.strip():
132
+ print(" No text extracted from any page.")
133
+ return "ERROR: PDFからテキストを抽出できませんでした。画像ベースのPDFかもしれません。" # プレフィックスを追加
134
+
135
+ print(f" Total text extracted (length: {len(text)}).")
136
+ return text
137
+ except Exception as e:
138
+ print(f" Error during PDF reading: {e}")
139
+ return f"ERROR: PDFの読み込み中にエラーが発生しました: {e}" # プレフィックスを追加
140
+
141
+ # def extract_text_from_pdf(pdf_file_path):
142
+ # """PDFファイルからテキストを抽出する (pdfminer.sixを使用)"""
143
+ # try:
144
+ # # pdfminer.six の extract_text 関数を使用
145
+ # text = pdfminer_extract_text(pdf_file_path)
146
+ # if not text.strip():
147
+ # return "PDFからテキストを抽出できませんでした。画像ベースのPDFかもしれません。"
148
+ # return text
149
+ # except Exception as e:
150
+ # return f"PDFの読み込み中にエラーが発生しました: {e}"
151
+
152
+ def get_llm_response(selected_llm, query, context, source_code_to_check):
153
+ """選択されたLLMを使用して質問に回答する"""
154
+ system_prompt = "あなたは提供されたコンテキスト(ソースコードチェックリスト)とレビュー対象のソースコードに基づいて、ソースコードをチェックし、その結果を返す有益なアシスタントです。チェックリストの項目ごとにソースコードを評価し、具体的な指摘と改善案を提示してください。コンテキストに情報がない場合は、「提供された情報からは回答できません。」と答えてください。"
155
+ user_content = f"ソースコードチェックリスト:\n{context}\n\nレビュー対象のソースコード:\n```\n{source_code_to_check}\n```\n\n質問: {query}\n\nチェック結果:"
156
+
157
+ try:
158
+ if selected_llm == "Ollama":
159
+ if not client_ollama:
160
+ return "Ollamaクライアントが初期化されていません。"
161
+ messages = [
162
+ {"role": "system", "content": system_prompt},
163
+ {"role": "user", "content": user_content}
164
+ ]
165
+ print(f"Ollamaモデル '{OLLAMA_MODEL_NAME}' にリクエストを送信中...")
166
+ response = client_ollama.chat(
167
+ model=OLLAMA_MODEL_NAME,
168
+ messages=messages,
169
+ options={
170
+ "temperature": 0.5,
171
+ "num_predict": 2000
172
+ }
173
+ )
174
+ if 'message' in response and 'content' in response['message']:
175
+ return response['message']['content'].strip()
176
+ else:
177
+ return f"Ollamaからの応答形式が不正です: {response}"
178
+
179
+ elif selected_llm == "GPT":
180
+ if not client_openai:
181
+ return "OpenAI APIキーが設定されていないため、GPTモデルは利用できません。"
182
+ messages = [
183
+ {"role": "system", "content": system_prompt},
184
+ {"role": "user", "content": user_content}
185
+ ]
186
+ print(f"GPTモデル '{OPENAI_MODEL_NAME}' にリクエストを送信中...")
187
+ response = client_openai.chat.completions.create(
188
+ model=OPENAI_MODEL_NAME,
189
+ messages=messages,
190
+ temperature=0.5,
191
+ max_tokens=2000
192
+ )
193
+ return response.choices[0].message.content.strip()
194
+
195
+ elif selected_llm == "Anthropic":
196
+ if not client_anthropic:
197
+ return "Anthropic APIキーが設定されていないため、Anthropicモデルは利用できません。"
198
+ messages = [
199
+ {"role": "user", "content": user_content}
200
+ ]
201
+ print(f"Anthropicモデル '{ANTHROPIC_MODEL_NAME}' にリクエストを送信中...")
202
+ response = client_anthropic.messages.create(
203
+ model=ANTHROPIC_MODEL_NAME,
204
+ max_tokens=2000,
205
+ temperature=0.5,
206
+ system=system_prompt, # Anthropicはsystemプロンプトを直接引数で渡す
207
+ messages=messages
208
+ )
209
+ return response.content[0].text.strip()
210
+
211
+ elif selected_llm == "Google Gemini":
212
+ if not client_gemini:
213
+ return "Google APIキーが設定されていないため、Geminiモデルは利用できません。"
214
+ # Geminiのsystem instructionはまだベータ版で、messagesと併用できない場合があるため、
215
+ # system_promptをuser_contentの先頭に結合する形式にする。
216
+ full_user_content = f"{system_prompt}\n\n{user_content}"
217
+ messages = [
218
+ {"role": "user", "parts": [full_user_content]}
219
+ ]
220
+ print(f"Google Geminiモデル '{GOOGLE_MODEL_NAME}' にリクエストを送信中...")
221
+ response = client_gemini.generate_content(
222
+ messages,
223
+ generation_config=genai.types.GenerationConfig(
224
+ temperature=0.5,
225
+ max_output_tokens=2000
226
+ )
227
+ )
228
+ return response.text.strip()
229
+
230
+ else:
231
+ return "無効なLLMが選択されました。"
232
+
233
+ except Exception as e:
234
+ print(f"LLM ({selected_llm}) の呼び出し中にエラーが発生しました: {e}")
235
+ return f"LLM ({selected_llm}) の呼び出し中にエラーが発生しました: {e}"
236
+
237
+ def upload_pdf_and_process(pdf_files):
238
+ """複数のPDFファイルをアップロードし、テキストを抽出し、ChromaDBに登録する"""
239
+ if not pdf_files:
240
+ print("No PDF files uploaded.")
241
+ return "PDFファイルがアップロードされていません。", gr.update(interactive=False), gr.update(interactive=False)
242
+
243
+ processed_files_count = 0
244
+ total_chunks_added = 0
245
+ all_status_messages = []
246
+
247
+ for pdf_file in pdf_files:
248
+ try:
249
+ pdf_path = pdf_file.name
250
+ file_name = os.path.basename(pdf_path)
251
+ all_status_messages.append(f"PDFファイル '{file_name}' を処理中...")
252
+ print(f"Processing PDF: {file_name} (Temporary Path: {pdf_path})")
253
+
254
+ # 1. PDFからテキストを抽出
255
+ raw_text = extract_text_from_pdf(pdf_path)
256
+
257
+ # --- デバッグ用追加コード (前回のデバッグで追加したものは残しておくと良いでしょう) ---
258
+ print(f"DEBUG: raw_text received from extract_text_from_pdf (length: {len(raw_text)})")
259
+ print(f"DEBUG: raw_text starts with: '{raw_text[:100].replace('\n', ' ')}'")
260
+ print(f"DEBUG: 'エラー' in raw_text: {'エラー' in raw_text}")
261
+ print(f"DEBUG: '抽出できませんでした' in raw_text: {'抽出できませんでした' in raw_text}")
262
+ print(f"DEBUG: 'PDFにページが含まれていません' in raw_text: {'PDFにページが含まれていません' in raw_text}")
263
+ # --- デバッグ情報ここまで ---
264
+
265
+ # エラープレフィックスでチェックするように変更
266
+ if raw_text.startswith("ERROR:"): # ここを変更
267
+ all_status_messages.append(raw_text)
268
+ print(f"Error during text extraction from {file_name}: {raw_text}") # ログメッセージも変更
269
+ continue # 次のファイルへ
270
+
271
+ # --- デバッグ用追加コード ---
272
+ print(f"\n--- Raw text extracted from {file_name} (length: {len(raw_text)}, first 500 chars) ---")
273
+ print(raw_text[:500])
274
+ print(f"--- End of raw text from {file_name} ---\n")
275
+
276
+ # 2. テキストをチャンクに分割
277
+ chunks = text_splitter.split_text(raw_text)
278
+ if not chunks:
279
+ all_status_messages.append(f"'{file_name}' から有効なテキストチャンクを抽出できませんでした。")
280
+ print(f"No valid chunks extracted from {file_name}.")
281
+ continue # 次のファイルへ
282
+
283
+ # 3. チャンクをChromaDBに登録
284
+ documents = chunks
285
+ metadatas = [{"source": file_name, "chunk_index": i} for i in range(len(chunks))]
286
+ ids = [str(uuid.uuid4()) for _ in range(len(chunks))]
287
+ collection.add(
288
+ documents=documents,
289
+ metadatas=metadatas,
290
+ ids=ids
291
+ )
292
+ processed_files_count += 1
293
+ total_chunks_added += len(chunks)
294
+ all_status_messages.append(f"PDFファイル '{file_name}' の処理が完了しました。{len(chunks)}個のチャンクがデータベースに登録されました。")
295
+ print(f"Finished processing {file_name}. Added {len(chunks)} chunks.")
296
+
297
+ except Exception as e:
298
+ all_status_messages.append(f"PDFファイル '{os.path.basename(pdf_file.name)}' 処理中に予期せぬエラーが発生しました: {e}")
299
+ print(f"Unexpected error during processing {os.path.basename(pdf_file.name)}: {e}")
300
+ continue # 次のファイルへ
301
+
302
+ final_status_message = f"{processed_files_count}個のPDFファイルの処理が完了しました。合計{total_chunks_added}個のチャンクがデータベースに登���されました。質問とソースコードを入力してください。\n\n" + "\n".join(all_status_messages)
303
+ return final_status_message, gr.update(interactive=True), gr.update(interactive=True)
304
+
305
+ def answer_question(question, source_code, selected_llm):
306
+ """ChromaDBから関連情報を取得し、選択されたLLMで質問に回答する"""
307
+ if not question and not source_code:
308
+ return "質問またはレビュー対象のソースコードを入力してください。", ""
309
+
310
+ if collection.count() == 0:
311
+ return "PDFがまだアップロードされていないか、処理されていません。まずPDFをアップロードしてください。", ""
312
+
313
+ try:
314
+ print(f"Searching ChromaDB for question: {question}")
315
+ results = collection.query(
316
+ query_texts=[question],
317
+ n_results=8
318
+ )
319
+ context_chunks = results['documents'][0] if results['documents'] else []
320
+ if not context_chunks:
321
+ print("No relevant context chunks found in ChromaDB.")
322
+ return "関連する情報が見つかりませんでした。質問を明確にするか、別のPDFを試してください。", ""
323
+
324
+ context = "\n\n".join(context_chunks)
325
+ print(f"Retrieved context (first 500 chars):\n{context[:500]}...")
326
+
327
+ answer = get_llm_response(selected_llm, question, context, source_code)
328
+ return answer, context
329
+ except Exception as e:
330
+ print(f"質問応答中に予期せぬエラーが発生しました: {e}")
331
+ return f"質問応答中に予期せぬエラーが発生しました: {e}", ""
332
+
333
+ # --- Gradio UIの構築 ---
334
+ with gr.Blocks() as gradioUI:
335
+ gr.Markdown(
336
+ f"""
337
+ # PDF Q&A with Local LLM (Ollama: {OLLAMA_MODEL_NAME}) and Vector Database
338
+ PDFファイルとしてソースコードチェックリストをアップロードし、レビューしたいソースコードを入力してください。
339
+ **複数のPDFファイルを同時にアップロードできます。**
340
+ 利用するLLMを選択してください。
341
+ """
342
+ )
343
+
344
+ with gr.Row():
345
+ with gr.Column():
346
+ pdf_input = gr.File(label="PDFドキュメントをアップロード", file_types=[".pdf"], file_count="multiple")
347
+ upload_status = gr.Textbox(label="ステータス", interactive=False, value="PDFをアップロードしてください。", lines=5)
348
+
349
+ with gr.Column():
350
+ # LLM選択コンポーネント
351
+ llm_options = ["Ollama"]
352
+ if client_openai:
353
+ llm_options.append("GPT")
354
+ if client_anthropic:
355
+ llm_options.append("Anthropic")
356
+ if client_gemini:
357
+ llm_options.append("Google Gemini")
358
+
359
+ llm_choice = gr.Radio(
360
+ llm_options,
361
+ label="使用するLLMを選択",
362
+ value=llm_options[0] if llm_options else None, # 利用可能な最初のLLMをデフォルトにする
363
+ interactive=True
364
+ )
365
+
366
+ source_code_input = gr.Code(
367
+ label="レビュー対象のソースコード (ここにソースコードを貼り付けてください)",
368
+ value="",
369
+ language="python",
370
+ interactive=False, # PDFアップロード後に有効化
371
+ lines=15
372
+ )
373
+ question_input = gr.Textbox(label="レビュー指示(例: セキュリティの観点からレビュー)", placeholder="特定の観点からのレビュー指示を入力してください(任意)。", interactive=False) # PDFアップロード後に有効化
374
+
375
+ review_button = gr.Button("レビュー開始")
376
+
377
+ answer_output = gr.Markdown(label="レビュー結果")
378
+ retrieved_context_output = gr.Textbox(label="取得されたチェックリスト項目", interactive=False, lines=10)
379
+
380
+ pdf_input.upload(
381
+ upload_pdf_and_process,
382
+ inputs=[pdf_input],
383
+ outputs=[upload_status, question_input, source_code_input]
384
+ )
385
+
386
+ review_button.click(
387
+ answer_question,
388
+ inputs=[question_input, source_code_input, llm_choice],
389
+ outputs=[answer_output, retrieved_context_output]
390
+ )
391
+
392
+ gradioUI.launch(server_name="localhost", server_port=7860)
app_sourcecodereview.py ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ from pypdf import PdfReader
4
+ from sentence_transformers import SentenceTransformer
5
+ import chromadb
6
+ from chromadb.utils import embedding_functions
7
+ import ollama # Ollamaライブラリをインポート
8
+ from langchain_text_splitters import RecursiveCharacterTextSplitter
9
+ import uuid # For generating unique IDs for chunks
10
+
11
+ # --- Ollamaクライアントの初期化 ---
12
+ client_ollama = ollama.Client()
13
+
14
+ OLLAMA_MODEL_NAME = "llama3.2"
15
+ # OLLAMA_MODEL_NAME = "llama3:8b-instruct-q4_0"
16
+
17
+ # --- 埋め込みモデルの初期化 ---
18
+ # 重複定義を削除し、1回のみ初期化
19
+ embedding_model = SentenceTransformer('pkshatech/GLuCoSE-base-ja') # 日本語対応の埋め込みモデル
20
+
21
+ # --- ChromaDBのカスタム埋め込み関数 ---
22
+ # 重複定義を削除し、1回のみ定義
23
+ class SBERTEmbeddingFunction(embedding_functions.EmbeddingFunction):
24
+ def __init__(self, model):
25
+ self.model = model
26
+ def __call__(self, texts):
27
+ # sentence-transformersモデルはnumpy配列を返すため、tolist()でPythonリストに変換
28
+ return self.model.encode(texts).tolist()
29
+
30
+ sbert_ef = SBERTEmbeddingFunction(embedding_model)
31
+
32
+ # --- ChromaDBクライアントとコレクションの初期化 ---
33
+ # インメモリモードで動作させ、アプリケーション起動時にコレクションをリセットします。
34
+ # グローバル変数としてクライアントを保持
35
+ client = chromadb.Client()
36
+ collection_name = "pdf_documents_collection"
37
+
38
+ # アプリケーション起動時にコレクションが存在すれば削除し、新しく作成する
39
+ # (インメモリDBはセッションごとにリセットされるため、これは初回起動時のみ意味を持つ)
40
+ try:
41
+ client.delete_collection(name=collection_name)
42
+ print(f"既存のChromaDBコレクション '{collection_name}' を削除しました。")
43
+ except Exception as e:
44
+ # コレクションが存在しない場合はエラーになるので無視。デバッグ用にメッセージは出力。
45
+ print(f"ChromaDBコレクション '{collection_name}' の削除に失敗しました (存在しないか、その他のエラー): {e}")
46
+ pass
47
+
48
+ collection = client.get_or_create_collection(name=collection_name, embedding_function=sbert_ef)
49
+ print(f"ChromaDBコレクション '{collection_name}' を初期化しました。")
50
+
51
+ text_splitter = RecursiveCharacterTextSplitter(
52
+ chunk_size=1000, # チャンクの最大文字数
53
+ chunk_overlap=150, # チャンク間のオーバーラップ文字数
54
+ length_function=len, # 文字数で長さを計算
55
+ separators=["\n\n", "\n", " ", ""] # 分割の優先順位
56
+ )
57
+
58
+ # --- ヘルパー関数 ---
59
+ def extract_text_from_pdf(pdf_file_path):
60
+ """PDFファイルからテキストを抽出する"""
61
+ try:
62
+ reader = PdfReader(pdf_file_path)
63
+ text = ""
64
+ for page in reader.pages:
65
+ page_text = page.extract_text()
66
+ if page_text: # ページが空でなければ追加
67
+ text += page_text + "\n"
68
+ if not text.strip(): # 全ページからテキストが抽出できなかった場合
69
+ return "PDFからテキストを抽出できませんでした。画像ベースのPDFかもしれません。"
70
+ return text
71
+ except Exception as e:
72
+ return f"PDFの読み込み中にエラーが発生しました: {e}"
73
+
74
+ def get_ollama_response(query, context, source_code_to_check):
75
+ """Ollamaモデルを使用して質問に回答する"""
76
+ messages = [
77
+ {"role": "system", "content": "あなたは提供されたコンテキスト(ソースコードチェックリスト)とレビュー対象のソースコードに基づいて、ソースコードをチェックし、その結果を返す有益なアシスタントです。チェックリストの項目ごとにソースコードを評価し、具体的な指摘と改善案を提示してください。コンテキストに情報がない場合は、「提供された情報からは回答できません。」と答えてください。"},
78
+ {"role": "user", "content": f"ソースコードチェックリスト:\n{context}\n\nレビュー対象のソースコード:\n```\n{source_code_to_check}\n```\n\n質問: {query}\n\nチェック結果:"}
79
+ ]
80
+ try:
81
+ print(f"Ollamaモデル '{OLLAMA_MODEL_NAME}' にリクエストを送信中...")
82
+ response = client_ollama.chat(
83
+ model=OLLAMA_MODEL_NAME,
84
+ messages=messages,
85
+ options={
86
+ "temperature": 0.5,
87
+ "num_predict": 2000 # 回答の最大トークン数
88
+ }
89
+ )
90
+ print(f"Ollamaからの生応答: {response}") # デバッグ用にOllamaの生レスポンスを出力
91
+
92
+ if 'message' in response and 'content' in response['message']:
93
+ return response['message']['content'].strip()
94
+ else:
95
+ print(f"Ollamaからの応答形式が不正です: {response}")
96
+ return "Ollamaモデルからの応答形式が不正です。詳細をコンソールログで確認してください。"
97
+ except ollama.ResponseError as e: # Ollama固有のエラーを捕捉
98
+ print(f"Ollama APIエラーが発生しました: {e}")
99
+ return f"Ollamaモデルの呼び出し中にAPIエラーが発生しました: {e}\nOllamaサーバーが起動しているか、モデル '{OLLAMA_MODEL_NAME}' がインストールされているか確認してください。"
100
+ except Exception as e: # その他の予期せぬエラー
101
+ print(f"Ollamaモデルの呼び出し中に予期せぬエラーが発生しました: {e}")
102
+ return f"Ollamaモデルの呼び出し中に予期せぬエラーが発生しました: {e}"
103
+
104
+
105
+ def upload_pdf_and_process(pdf_files):
106
+ """複数のPDFファイルをアップロードし、テキストを抽出し、ChromaDBに登録する"""
107
+ if not pdf_files:
108
+ return "PDFファイルがアップロードされていません。", gr.update(interactive=False), gr.update(interactive=False)
109
+
110
+ processed_files_count = 0
111
+ total_chunks_added = 0
112
+ all_status_messages = []
113
+
114
+ for pdf_file in pdf_files:
115
+ try:
116
+ pdf_path = pdf_file.name
117
+ file_name = os.path.basename(pdf_path)
118
+ all_status_messages.append(f"PDFファイル '{file_name}' を処理中...")
119
+ print(f"Processing PDF: {file_name}")
120
+
121
+ # 1. PDFからテキストを抽出
122
+ raw_text = extract_text_from_pdf(pdf_path)
123
+ if "エラー" in raw_text or "抽出できませんでした" in raw_text:
124
+ all_status_messages.append(raw_text)
125
+ print(f"Error extracting text from {file_name}: {raw_text}")
126
+ continue # 次のファイルへ
127
+
128
+ # 2. テキストをチャンクに分割
129
+ chunks = text_splitter.split_text(raw_text)
130
+ if not chunks:
131
+ all_status_messages.append(f"'{file_name}' から有効なテキストチャンクを抽出できませんでした。")
132
+ print(f"No valid chunks extracted from {file_name}.")
133
+ continue # 次のファイルへ
134
+
135
+ # 3. チャンクをChromaDBに登録
136
+ documents = chunks
137
+ metadatas = [{"source": file_name, "chunk_index": i} for i in range(len(chunks))]
138
+ ids = [str(uuid.uuid4()) for _ in range(len(chunks))]
139
+ collection.add(
140
+ documents=documents,
141
+ metadatas=metadatas,
142
+ ids=ids
143
+ )
144
+ processed_files_count += 1
145
+ total_chunks_added += len(chunks)
146
+ all_status_messages.append(f"PDFファイル '{file_name}' の処理が完了しました。{len(chunks)}個のチャンクがデータベースに登録されました。")
147
+ print(f"Finished processing {file_name}. Added {len(chunks)} chunks.")
148
+
149
+ except Exception as e:
150
+ all_status_messages.append(f"PDFファイル '{os.path.basename(pdf_file.name)}' 処理中に予期せぬエラーが発生しました: {e}")
151
+ print(f"Unexpected error during processing {os.path.basename(pdf_file.name)}: {e}")
152
+ continue # 次のファイルへ
153
+
154
+ final_status_message = f"{processed_files_count}個のPDFファイルの処理が完了しました。合計{total_chunks_added}個のチャンクがデータベースに登録されました。質問とソースコードを入力してください。\n\n" + "\n".join(all_status_messages)
155
+ return final_status_message, gr.update(interactive=True), gr.update(interactive=True)
156
+
157
+ def answer_question(question, source_code):
158
+ """ChromaDBから関連情報を取得し、Ollamaモデルで質問に回答する"""
159
+ if not question and not source_code: # 質問またはソースコードのいずれかがあればOK
160
+ return "質問またはレビュー対象のソースコードを入力してください。", ""
161
+
162
+ if collection.count() == 0:
163
+ return "PDFがまだアップロードされていないか、処理されていません。まずPDFをアップロードしてください。", ""
164
+
165
+ try:
166
+ print(f"Searching ChromaDB for question: {question}") # デバッグ出力
167
+ results = collection.query(
168
+ query_texts=[question],
169
+ n_results=8 # 上位8つの関連チャンクを取得
170
+ )
171
+ context_chunks = results['documents'][0] if results['documents'] else []
172
+ if not context_chunks:
173
+ print("No relevant context chunks found in ChromaDB.")
174
+ return "関連する情報が見つかりませんでした。質問を明確にするか、別のPDFを試してください。", ""
175
+
176
+ context = "\n\n".join(context_chunks)
177
+ print(f"Retrieved context (first 500 chars):\n{context[:500]}...") # デバッグ用にコンテキストの一部を出力
178
+
179
+ answer = get_ollama_response(question, context, source_code) # ���数名を変更
180
+ return answer, context
181
+ except Exception as e:
182
+ print(f"質問応答中に予期せぬエラーが発生しました: {e}")
183
+ return f"質問応答中に予期せぬエラーが発生しました: {e}", ""
184
+
185
+ # --- Gradio UIの構築 ---
186
+ with gr.Blocks() as gradioUI:
187
+ gr.Markdown(
188
+ f"""
189
+ # PDF Q&A with Local LLM (Ollama: {OLLAMA_MODEL_NAME}) and Vector Database
190
+ PDFファイルとしてソースコードチェックリストをアップロードし、レビューしたいソースコードを入力してください。
191
+ **複数のPDFファイルを同時にアップロードできます。**
192
+ ローカルのOllama ({OLLAMA_MODEL_NAME}) を使用しています。
193
+ """
194
+ )
195
+
196
+ with gr.Row():
197
+ with gr.Column():
198
+ pdf_input = gr.File(label="PDFドキュメントをアップロード", file_types=[".pdf"], file_count="multiple")
199
+ upload_status = gr.Textbox(label="ステータス", interactive=False, value="PDFをアップロードしてください。", lines=5)
200
+
201
+ with gr.Column():
202
+ source_code_input = gr.Code(
203
+ label="レビュー対象のソースコード (ここにソースコードを貼り付けてください)",
204
+ value="",
205
+ language="python",
206
+ interactive=True,
207
+ lines=15
208
+ )
209
+ question_input = gr.Textbox(label="レビュー指示(例: セキュリティの観点からレビュー)", placeholder="特定の観点からのレビュー指示を入力してください(任意)。", interactive=False)
210
+
211
+ review_button = gr.Button("レビュー開始")
212
+
213
+ answer_output = gr.Markdown(label="レビュー結果")
214
+ retrieved_context_output = gr.Textbox(label="取得されたチェックリスト項目", interactive=False, lines=10)
215
+
216
+ pdf_input.upload(
217
+ upload_pdf_and_process,
218
+ inputs=[pdf_input],
219
+ outputs=[upload_status, question_input, source_code_input]
220
+ )
221
+
222
+ review_button.click(
223
+ answer_question,
224
+ inputs=[question_input, source_code_input],
225
+ outputs=[answer_output, retrieved_context_output]
226
+ )
227
+
228
+ gradioUI.launch(server_name="0.0.0.0", server_port=7860)
checklist/c_code_review_checklist.pdf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1b8734d77b148a27952ec432e05f4182382bcc078e1fff4c351de0698f5843be
3
+ size 251644
checklist/c_code_review_checklist.txt ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 全般
2
+ コードは実装が必要なものですか?
3
+
4
+ オープンソースライブラリなど、広く使われている、あるいは信頼性の高いコードが利用できないか検討しましょう。
5
+ コードは動作しますか?
6
+
7
+ コミット、マージする前に、最低限の動作を確認しましょう。
8
+ コードを動作させるための手順は明確ですか?
9
+
10
+ 最低限、コードの実行方法、依存関係をREADME.mdなどに書きましょう。
11
+ コードは理解しやすいように記述されていますか?
12
+
13
+ 数ヶ月後の自分が読んでも理解できそうですか?
14
+ マジックナンバーが埋め込まれていませんか?
15
+ 定数化するなど、名称を与えることができないか検討しましょう。
16
+ コードは長すぎませんか?
17
+
18
+ 関数(メソッド)が数十行を越える場合、分割できないかどうか検証しましょう。
19
+ 不要なコードが残っていませんか?
20
+
21
+ テストコード
22
+ テストコードは記述されていますか?
23
+
24
+ 可能な限り記述しましょう。
25
+ テストコードの実行結果はグリーン(正常)ですか?
26
+
27
+ レッド(失敗)なのであれば、その状態で本当にコミットしなければならないのかどうか再考しましょう。
28
+ コーディングスタイル / 命名規則
29
+ コーディングスタイルは統一されていますか?
30
+
31
+ コーディング標準(コーディング規約)が制定されている場合、その標準に従っていますか?
32
+ 例: Python - PEP-8、Google Python Style Guide
33
+ 例: C++ - Google C++ Style Guide
34
+ ネストが深くなりすぎていませんか?
35
+
36
+ 識別子
37
+ スペルは正しいですか?
38
+
39
+ camelCase、PascalCase、snake_caseなど、それぞれの表現と意味は統一されていますか?
40
+
41
+ 名称 別名 代表的な用途
42
+ camelCase lowerCamelCase Javaの変数名、仮引数名。JavaScriptのプロパティ名。
43
+ PascalCase UpperCamelCase Java、C++、Rubyのクラス名。
44
+ snake_case underline_style、lower_case、lower_case_with_underscores Rubyのメソッド名、変数名。
45
+ UPPER_CASE UPPER_CASE_WITH_UNDERSCORES C言語のマクロ名。Javaの定数名。
46
+ 単数形、複数形は適切に使い分けられていますか?
47
+
48
+ tmp、bufferなど、汎用的過ぎる名称は使われていませんか?
49
+
50
+ より具体的な名称にできないかどうか検討しましょう。
51
+ コード内で利用されている名称は統一されていますか?
52
+
53
+ 略語を用いている場合、それは一般的な略語ですか?
54
+
55
+ 略語を用いている場合、それは展開しても十分短い名前ではないですか?
56
+
57
+ 対称的な処理を行っている場合、対称的な名前になっていますか?
58
+
59
+ セキュリティ
60
+ パスワード、秘密鍵などは埋め込まれていませんか?
61
+ ファイル
62
+ 絶対パスが埋め込まれていませんか?
63
+
64
+ カレントディレクトリに依存したコードになっていませんか?
65
+
66
+ カレントディレクトリに依存していると、実行する環境を整えるのが大変になります。
67
+ スクリプトファイルからの相対パス、何らかの基準パスからの相対パスに書き換えることができないか検討しましょう。
68
+ ファイルは適切にクローズされていますか?
69
+
70
+ コメント
71
+ そのコメントは必要ですか?
72
+
73
+ コメントで補足するより、元のコードをより分かりやすく書き換えることができないか検証しましょう。
74
+ コードを自然言語に書き直しただけのコメントになっていませんか?
75
+
76
+ コメントにはコードで表現できないこと(そのアルゴリズムを採用した理由、など)を記述しましょう。
77
+ コメントアウトされたコードは残っていませんか?
78
+
79
+ データ型
80
+ 配列であるべきデータですか?
81
+ 複数の値を渡したいという理由だけで配列が使われていませんか?
82
+ タプル、ハッシュ(ディクショナリ)など、他のデータ型を検討しましょう。
83
+ コマンド / ツール
84
+ 適切な終了コードを返していますか?
85
+
86
+ MakefileやDockerfileでコマンドを呼び出す場合、終了コードが重要な意味を持ちます。
87
+ 異常を適切に伝えるために、0以外の終了コードを返すことを検討しましょう。
88
+ 標準出力と標準エラー出力を適切に使い分けていますか?
89
+
90
+ その他
91
+ 乱数を使用する場合、シード(種)は適切ですか?
92
+ 再現性が必要な場合、シードを固定する手段を提供しましょう。
checklist/chang_checklist.pdf ADDED
Binary file (79.4 kB). View file
 
checklist/clang_checklist.md ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 以下を通常のテキスト表示にしてください。
2
+ 1. 堅牢性(エラーハンドリング・安全性)
3
+ 入力値の検証:
4
+ 関数(例: find_max, find_min)に渡される引数(arr, size)が、期待される有効な値であるかを確認していますか?
5
+ 例: arr が NULL ポインタでないか? size が 0 以上であるか?
6
+ もし無効な値が渡された場合、プログラムがクラッシュしたり、予期せぬ動作をしたりする可能性はありませんか?
7
+ 境界条件の考慮:
8
+ 配列の要素数が1つだけの場合、空の配列の場合など、極端なケースで正しく動作しますか?
9
+ エラー処理:
10
+ 関数内で問題が発生した場合(例: 無効な入力があった場合)、どのように呼び出し元にエラーを伝えていますか?(戻り値、エラーコードなど)
11
+ 2. 可読性・保守性
12
+ 命名規則:
13
+ 変数名、関数名が、その役割や目的を明確に表す、分かりやすい名前になっていますか?
14
+ 例: n よりも array_count の方が分かりやすい、など。
15
+ 命名規則(例: 小文字とアンダースコアで区切る snake_case)が一貫していますか?
16
+ コメント:
17
+ 複雑な処理や、なぜそのように実装したのかが分かりにくい箇所に、適切なコメントが書かれていますか?
18
+ 関数の目的、引数(入力)、戻り値(出力)、そしてその関数を使う上での注意点などが、コメントで説明されていますか?
19
+ マジックナンバー:
20
+ プログラム中に、意味が分からない数字(例: 6 など)が直接書かれていませんか?
21
+ そのような数字は、定数(#define や const)として名前をつけて定義し、その名前を使っていますか?
22
+ コードの構造:
23
+ 一つの関数やブロックが長すぎず、一つの役割に集中していますか?(「単一責任の原則」)
24
+ コードが読みやすいように、適切な場所で改行や空白行が使われていますか?
25
+ 3. 効率性
26
+ アルゴリズムの選択:
27
+ 現在の処理方法よりも、もっと効率的に同じ結果を得られる方法はありませんか?
28
+ 例: ループの回数を減らす、計算をまとめるなど。
29
+ 無駄な処理:
30
+ 同じ計算が何度も繰り返されていませんか?
31
+ 必要のないメモリの確保やコピーが発生していませんか?
32
+ 4. コーディングスタイル
33
+ インデント:
34
+ コードの階層構造(ブロックの深さ)に合わせて、一貫したインデント(字下げ)が使われていますか?(例: スペース2つ、スペース4つ、タブなど)
35
+ 括弧の位置:
36
+ { や } といった括弧の位置が、プロジェクトやチームのルール(または一般的な慣習)に沿って一貫していますか?
37
+ スペースの利用:
38
+ 演算子(+, =, > など)の周りや、カンマの後ろなどに、適切なスペースが使われていて読みやすいですか?
39
+ ヘッダーコメント:
40
+ ファイルの先頭に、ファイルの内容や著作権情報などを説明するコメントがありますか?(これはプロジェクトによって有無が異なります)
checklist/clang_checklist.pdf ADDED
Binary file (75.7 kB). View file
 
checklist/clang_checklist_002.pdf ADDED
Binary file (6.4 kB). View file
 
checklist/clang_sample.rtfd/TXT.rtf ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {\rtf1\ansi\ansicpg932\cocoartf2865
2
+ \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
3
+ {\colortbl;\red255\green255\blue255;}
4
+ {\*\expandedcolortbl;;}
5
+ \paperw11900\paperh16840\margl1440\margr1440\vieww11520\viewh8400\viewkind0
6
+ \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
7
+
8
+ \f0\fs24 \cf0 #include <stdio.h> // \uc0\u27161 \u28310 \u20837 \u20986 \u21147 \u38306 \u25968 \u65288 printf, scanf, gets, fopen, fclose, fprintf\u12394 \u12393 \u65289 \u12434 \u20351 \u12358 \u12383 \u12417 \
9
+ #include <stdlib.h> // \uc0\u19968 \u33324 \u12518 \u12540 \u12486 \u12451 \u12522 \u12486 \u12451 \u38306 \u25968 \u65288 malloc, free, exit\u12394 \u12393 \u65289 \u12434 \u20351 \u12358 \u12383 \u12417 \
10
+ #include <string.h> // \uc0\u25991 \u23383 \u21015 \u25805 \u20316 \u38306 \u25968 \u65288 strlen, strcpy\u12394 \u12393 \u65289 \u12434 \u20351 \u12358 \u12383 \u12417 \
11
+ #include <ctype.h> // \uc0\u25991 \u23383 \u31278 \u21028 \u21029 \u12539 \u22793 \u25563 \u38306 \u25968 \u65288 toupper\u12394 \u12393 \u65289 \u12434 \u20351 \u12358 \u12383 \u12417 \
12
+ \
13
+ // \uc0\u12464 \u12525 \u12540 \u12496 \u12523 \u22793 \u25968 \u65306 \u12503 \u12525 \u12464 \u12521 \u12512 \u20840 \u20307 \u12363 \u12425 \u12450 \u12463 \u12475 \u12473 \u12391 \u12365 \u12427 \u22793 \u25968 \
14
+ // \uc0\u12375 \u12363 \u12375 \u12289 \u23433 \u26131 \u12394 \u20351 \u29992 \u12399 \u12503 \u12525 \u12464 \u12521 \u12512 \u12434 \u35079 \u38609 \u12395 \u12375 \u12364 \u12385 \u12391 \u12377 \u12290 \
15
+ int global_counter = 0;\
16
+ \
17
+ // \uc0\u12510 \u12472 \u12483 \u12463 \u12490 \u12531 \u12496 \u12540 \u12398 \u23450 \u32681 \
18
+ // \uc0\u20170 \u22238 \u12399 \u24460 \u36848 \u12398 gets()\u12391 \u12496 \u12483 \u12501 \u12449 \u12458 \u12540 \u12496 \u12540 \u12501 \u12525 \u12540 \u12434 \u24341 \u12365 \u36215 \u12371 \u12377 \u12383 \u12417 \u12395 \u21033 \u29992 \u12375 \u12390 \u12356 \u12414 \u12377 \u12290 \
19
+ #define MAX_NAME_LEN 20\
20
+ \
21
+ // \uc0\u12518 \u12540 \u12470 \u12540 \u12398 \u21517 \u21069 \u12434 \u22823 \u25991 \u23383 \u12395 \u22793 \u25563 \u12377 \u12427 \u38306 \u25968 \
22
+ // \uc0\u12304 \u21839 \u38988 \u28857 \u65306 \u12513 \u12514 \u12522 \u12522 \u12540 \u12463 \u12305 \
23
+ // \uc0\u12371 \u12398 \u38306 \u25968 \u20869 \u12391 \u21205 \u30340 \u12395 \u30906 \u20445 \u12375 \u12383 \u12513 \u12514 \u12522 \u12434 \u21628 \u12403 \u20986 \u12375 \u20803 \u12391 \u35299 \u25918 \u12377 \u12427 \u12371 \u12392 \u12434 \u24536 \u12428 \u12390 \u12375 \u12414 \u12356 \u12364 \u12385 \u12391 \u12377 \u12290 \
24
+ char* toUpperCase(char* str) \{\
25
+ if (str == NULL) \{\
26
+ return NULL; // NULL\uc0\u12509 \u12452 \u12531 \u12479 \u12364 \u28193 \u12373 \u12428 \u12383 \u22580 \u21512 \u12399 NULL\u12434 \u36820 \u12377 \
27
+ \}\
28
+ \
29
+ // \uc0\u24341 \u25968 \u12391 \u28193 \u12373 \u12428 \u12383 \u25991 \u23383 \u21015 \u12392 \u21516 \u12376 \u38263 \u12373 \u12398 \u12513 \u12514 \u12522 \u12434 \u21205 \u30340 \u12395 \u30906 \u20445 \
30
+ char* upper_str = (char*)malloc(strlen(str) + 1); // +1\uc0\u12399 \u12492 \u12523 \u32066 \u31471 \u25991 \u23383 \u12398 \u12383 \u12417 \
31
+ \
32
+ if (upper_str == NULL) \{\
33
+ // \uc0\u12513 \u12514 \u12522 \u21106 \u12426 \u24403 \u12390 \u12364 \u22833 \u25943 \u12375 \u12383 \u22580 \u21512 \u12398 \u12456 \u12521 \u12540 \u20966 \u29702 \
34
+ perror("toUpperCase: \uc0\u12513 \u12514 \u12522 \u30906 \u20445 \u12395 \u22833 \u25943 \u12375 \u12414 \u12375 \u12383 ");\
35
+ // exit()\uc0\u12434 \u21628 \u12406 \u12392 \u12289 \u12381 \u12428 \u12414 \u12391 \u12395 \u30906 \u20445 \u12375 \u12383 \u12522 \u12477 \u12540 \u12473 \u12364 \u35299 \u25918 \u12373 \u12428 \u12378 \u12395 \u12503 \u12525 \u12464 \u12521 \u12512 \u12364 \u32066 \u20102 \u12377 \u12427 \u21487 \u33021 \u24615 \u12364 \u12354 \u12426 \u12414 \u12377 \u12290 \
36
+ exit(EXIT_FAILURE);\
37
+ \}\
38
+ \
39
+ // \uc0\u21508 \u25991 \u23383 \u12434 \u22823 \u25991 \u23383 \u12395 \u22793 \u25563 \
40
+ for (int i = 0; str[i] != '\\0'; i++) \{\
41
+ upper_str[i] = toupper((unsigned char)str[i]);\
42
+ \}\
43
+ upper_str[strlen(str)] = '\\0'; // \uc0\u12492 \u12523 \u32066 \u31471 \
44
+ \
45
+ // \uc0\u12371 \u12371 \u12391 \u30906 \u20445 \u12375 \u12383 upper_str\u12399 \u12289 \u21628 \u12403 \u20986 \u12375 \u20803 \u12391 free()\u12373 \u12428 \u12427 \u24517 \u35201 \u12364 \u12354 \u12426 \u12414 \u12377 \u12364 \u12289 \u12381 \u12398 \u35352 \u36848 \u12364 \u12354 \u12426 \u12414 \u12379 \u12435 \u12290 \
46
+ return upper_str; // \uc0\u26032 \u12375 \u12367 \u30906 \u20445 \u12375 \u12383 \u12513 \u12514 \u12522 \u12408 \u12398 \u12509 \u12452 \u12531 \u12479 \u12434 \u36820 \u12377 \
47
+ \}\
48
+ \
49
+ // \uc0\u21361 \u38522 \u12394 \u35336 \u31639 \u12434 \u23455 \u34892 \u12377 \u12427 \u38306 \u25968 \
50
+ // \uc0\u12304 \u21839 \u38988 \u28857 \u65306 \u12476 \u12525 \u38500 \u31639 \u12398 \u21487 \u33021 \u24615 \u12289 \u25972 \u25968 \u12458 \u12540 \u12496 \u12540 \u12501 \u12525 \u12540 \u12398 \u21487 \u33021 \u24615 \u12289 \u28961 \u39364 \u12394 \u12523 \u12540 \u12503 \u12305 \
51
+ int performDangerousCalculation(int a, int b) \{\
52
+ global_counter++; // \uc0\u12464 \u12525 \u12540 \u12496 \u12523 \u22793 \u25968 \u12434 \u26356 \u26032 \
53
+ \
54
+ int result = 0; // \uc0\u32080 \u26524 \u12434 \u21021 \u26399 \u21270 \
55
+ \
56
+ // \uc0\u12476 \u12525 \u38500 \u31639 \u12434 \u22238 \u36991 \u12375 \u12424 \u12358 \u12392 \u12399 \u12375 \u12390 \u12356 \u12427 \u12364 ...\
57
+ if (b != 0) \{\
58
+ // (a / b) + (a * b) * 1000000;\
59
+ // \uc0\u12300 a * b * 1000000\u12301 \u12398 \u37096 \u20998 \u12391 \u12289 int\u22411 \u12398 \u26368 \u22823 \u20516 \u12434 \u36229 \u12360 \u12390 \u12375 \u12414 \u12358 \u65288 \u25972 \u25968 \u12458 \u12540 \u12496 \u12540 \u12501 \u12525 \u12540 \u65289 \u21487 \u33021 \u24615 \u12364 \u12354 \u12426 \u12414 \u12377 \u12290 \
60
+ result = (a / b) + (a * b) * 1000000;\
61
+ \} else \{\
62
+ printf("\uc0\u35686 \u21578 : \u12476 \u12525 \u38500 \u31639 \u12434 \u22238 \u36991 \u12375 \u12414 \u12375 \u12383 \u12290 \\n");\
63
+ // \uc0\u12371 \u12398 \u22580 \u21512 \u12289 result\u12399 \u21021 \u26399 \u20516 \u12398 0\u12398 \u12414 \u12414 \u36820 \u12373 \u12428 \u12414 \u12377 \u12290 \
64
+ // \uc0\u21628 \u12403 \u20986 \u12375 \u20803 \u12391 \u12289 \u12371 \u12398 \u12476 \u12525 \u38500 \u31639 \u22238 \u36991 \u26178 \u12398 \u32080 \u26524 \u12364 \u24847 \u22259 \u12375 \u12383 \u12418 \u12398 \u12391 \u12354 \u12427 \u12363 \u30906 \u35469 \u12364 \u24517 \u35201 \u12391 \u12377 \u12290 \
65
+ \}\
66
+ \
67
+ // \uc0\u20309 \u12398 \u24847 \u21619 \u12418 \u12394 \u12356 \u12289 \u28961 \u39364 \u12394 \u12523 \u12540 \u12503 \
68
+ // CPU\uc0\u12469 \u12452 \u12463 \u12523 \u12434 \u28961 \u39364 \u12395 \u28040 \u36027 \u12377 \u12427 \u12384 \u12369 \u12391 \u12377 \u12290 \
69
+ for (int i = 0; i < 10000; i++) \{\
70
+ // \uc0\u20309 \u12418 \u12375 \u12394 \u12356 \
71
+ \}\
72
+ \
73
+ return result;\
74
+ \}\
75
+ \
76
+ // \uc0\u12501 \u12449 \u12452 \u12523 \u12395 \u12487 \u12540 \u12479 \u12434 \u26360 \u12365 \u36796 \u12416 \u38306 \u25968 \
77
+ // \uc0\u12304 \u21839 \u38988 \u28857 \u65306 \u12501 \u12449 \u12452 \u12523 \u12495 \u12531 \u12489 \u12523 \u12398 \u38281 \u12376 \u24536 \u12428 \u12289 \u12456 \u12521 \u12540 \u12495 \u12531 \u12489 \u12522 \u12531 \u12464 \u12398 \u19981 \u36275 \u12289 \u19978 \u26360 \u12365 \u12514 \u12540 \u12489 \u12305 \
78
+ void writeDataToFile(const char* filename, const char* name, int value) \{\
79
+ // "w"\uc0\u12514 \u12540 \u12489 \u12399 \u12289 \u12501 \u12449 \u12452 \u12523 \u12364 \u23384 \u22312 \u12377 \u12428 \u12400 \u20869 \u23481 \u12434 \u12377 \u12409 \u12390 \u28040 \u21435 \u12375 \u12289 \u26032 \u12375 \u12367 \u26360 \u12365 \u36796 \u12415 \u12414 \u12377 \u12290 \
80
+ // \uc0\u26082 \u23384 \u12398 \u12487 \u12540 \u12479 \u12434 \u24847 \u22259 \u12379 \u12378 \u19978 \u26360 \u12365 \u12375 \u12390 \u12375 \u12414 \u12358 \u21487 \u33021 \u24615 \u12364 \u12354 \u12426 \u12414 \u12377 \u12290 \
81
+ FILE* fp = fopen(filename, "w");\
82
+ \
83
+ if (fp == NULL) \{\
84
+ // \uc0\u12501 \u12449 \u12452 \u12523 \u12458 \u12540 \u12503 \u12531 \u22833 \u25943 \u26178 \u12398 \u12456 \u12521 \u12540 \u20966 \u29702 \u12290 \
85
+ // \uc0\u12456 \u12521 \u12540 \u12513 \u12483 \u12475 \u12540 \u12472 \u12399 \u20986 \u12377 \u12364 \u12289 \u21628 \u12403 \u20986 \u12375 \u20803 \u12395 \u12456 \u12521 \u12540 \u12434 \u20253 \u12360 \u12427 \u25163 \u27573 \u12364 \u12354 \u12426 \u12414 \u12379 \u12435 \u12290 \
86
+ printf("\uc0\u12456 \u12521 \u12540 : \u12501 \u12449 \u12452 \u12523 '%s' \u12434 \u26360 \u12365 \u36796 \u12415 \u29992 \u12395 \u38283 \u12369 \u12414 \u12379 \u12435 \u12391 \u12375 \u12383 \u12290 \\n", filename);\
87
+ return; // \uc0\u12456 \u12521 \u12540 \u12394 \u12398 \u12391 \u20966 \u29702 \u12434 \u20013 \u26029 \
88
+ \}\
89
+ \
90
+ fprintf(fp, "\uc0\u21517 \u21069 : %s\\n", name);\
91
+ fprintf(fp, "\uc0\u20516 : %d\\n", value);\
92
+ \
93
+ // \uc0\u12304 \u21839 \u38988 \u28857 \u12305 \
94
+ // \uc0\u12371 \u12371 \u12391 fclose(fp); \u12434 \u21628 \u12403 \u20986 \u12375 \u12390 \u12501 \u12449 \u12452 \u12523 \u12495 \u12531 \u12489 \u12523 \u12434 \u38281 \u12376 \u12427 \u24517 \u35201 \u12364 \u12354 \u12426 \u12414 \u12377 \u12364 \u12289 \u21628 \u12403 \u20986 \u12375 \u12390 \u12356 \u12414 \u12379 \u12435 \u12290 \
95
+ // \uc0\u12503 \u12525 \u12464 \u12521 \u12512 \u12364 \u32066 \u20102 \u12377 \u12427 \u12414 \u12391 \u12501 \u12449 \u12452 \u12523 \u12495 \u12531 \u12489 \u12523 \u12364 \u38281 \u12376 \u12425 \u12428 \u12378 \u12289 \u12522 \u12477 \u12540 \u12473 \u12522 \u12540 \u12463 \u12395 \u12388 \u12394 \u12364 \u12426 \u12414 \u12377 \u12290 \
96
+ \}\
97
+ \
98
+ // \uc0\u12525 \u12464 \u12501 \u12449 \u12452 \u12523 \u12395 \u12513 \u12483 \u12475 \u12540 \u12472 \u12434 \u36861 \u35352 \u12377 \u12427 \u38306 \u25968 \
99
+ // \uc0\u12304 \u21839 \u38988 \u28857 \u65306 \u12501 \u12449 \u12452 \u12523 \u12495 \u12531 \u12489 \u12523 \u12398 \u38281 \u12376 \u24536 \u12428 \u12305 \
100
+ void logMessage(const char* message) \{\
101
+ // "a"\uc0\u12514 \u12540 \u12489 \u12399 \u12289 \u12501 \u12449 \u12452 \u12523 \u12364 \u23384 \u22312 \u12377 \u12428 \u12400 \u26411 \u23614 \u12395 \u36861 \u35352 \u12375 \u12289 \u23384 \u22312 \u12375 \u12394 \u12369 \u12428 \u12400 \u26032 \u12375 \u12367 \u20316 \u25104 \u12375 \u12414 \u12377 \u12290 \
102
+ FILE* log_fp = fopen("app.log", "a");\
103
+ \
104
+ if (log_fp == NULL) \{\
105
+ printf("\uc0\u12456 \u12521 \u12540 : \u12525 \u12464 \u12501 \u12449 \u12452 \u12523 \u12434 \u38283 \u12369 \u12414 \u12379 \u12435 \u12391 \u12375 \u12383 \u12290 \\n");\
106
+ return;\
107
+ \}\
108
+ fprintf(log_fp, "[LOG] %s\\n", message);\
109
+ \
110
+ // \uc0\u12304 \u21839 \u38988 \u28857 \u12305 \
111
+ // \uc0\u12371 \u12371 \u12391 \u12418 fclose(log_fp); \u12434 \u21628 \u12403 \u20986 \u12375 \u12390 \u12501 \u12449 \u12452 \u12523 \u12495 \u12531 \u12489 \u12523 \u12434 \u38281 \u12376 \u12427 \u24517 \u35201 \u12364 \u12354 \u12426 \u12414 \u12377 \u12364 \u12289 \u21628 \u12403 \u20986 \u12375 \u12390 \u12356 \u12414 \u12379 \u12435 \u12290 \
112
+ \}\
113
+ \
114
+ \
115
+ int main() \{\
116
+ char name_buffer[MAX_NAME_LEN]; // \uc0\u12518 \u12540 \u12470 \u12540 \u12398 \u21517 \u21069 \u12434 \u26684 \u32013 \u12377 \u12427 \u12496 \u12483 \u12501 \u12449 \u65288 MAX_NAME_LEN = 20\u25991 \u23383 \u65289 \
117
+ int number_input;\
118
+ // char temp_input[256]; // gets()\uc0\u12398 \u12383 \u12417 \u12398 \u12467 \u12513 \u12531 \u12488 \u12450 \u12454 \u12488 \u12373 \u12428 \u12383 \u19968 \u26178 \u12496 \u12483 \u12501 \u12449 \
119
+ \
120
+ printf("\uc0\u12354 \u12394 \u12383 \u12398 \u21517 \u21069 \u12434 \u20837 \u21147 \u12375 \u12390 \u12367 \u12384 \u12373 \u12356 : ");\
121
+ // \uc0\u12304 \u37325 \u22823 \u12394 \u21839 \u38988 \u28857 \u65306 gets() \u12398 \u20351 \u29992 \u12305 \
122
+ // gets() \uc0\u12399 \u12289 \u20837 \u21147 \u12373 \u12428 \u12383 \u25991 \u23383 \u21015 \u12398 \u38263 \u12373 \u12434 \u12481 \u12455 \u12483 \u12463 \u12379 \u12378 \u12289 \u12496 \u12483 \u12501 \u12449 \u12398 \u12469 \u12452 \u12474 \u12434 \u36229 \u12360 \u12390 \u26360 \u12365 \u36796 \u12416 \u21487 \u33021 \u24615 \u12364 \u12354 \u12426 \u12414 \u12377 \u12290 \
123
+ // \uc0\u20363 \u12360 \u12400 \u12289 20\u25991 \u23383 \u20197 \u19978 \u12398 \u21517 \u21069 \u12434 \u20837 \u21147 \u12377 \u12427 \u12392 \u12289 name_buffer \u12398 \u22806 \u12395 \u12487 \u12540 \u12479 \u12364 \u26360 \u12365 \u36796 \u12414 \u12428 \u12289 \
124
+ // \uc0\u12503 \u12525 \u12464 \u12521 \u12512 \u12364 \u12463 \u12521 \u12483 \u12471 \u12517 \u12375 \u12383 \u12426 \u12289 \u24746 \u24847 \u12398 \u12354 \u12427 \u12467 \u12540 \u12489 \u12364 \u23455 \u34892 \u12373 \u12428 \u12383 \u12426 \u12377 \u12427 \u12300 \u12496 \u12483 \u12501 \u12449 \u12458 \u12540 \u12496 \u12540 \u12501 \u12525 \u12540 \u12301 \u12434 \u35480 \u30330 \u12375 \u12414 \u12377 \u12290 \
125
+ // \uc0\u12371 \u12398 \u38306 \u25968 \u12399 \u38750 \u24120 \u12395 \u21361 \u38522 \u12394 \u12398 \u12391 \u12289 \u32118 \u23550 \u12395 \u20351 \u29992 \u12375 \u12390 \u12399 \u12356 \u12369 \u12414 \u12379 \u12435 \u12290 \
126
+ gets(name_buffer);\
127
+ \
128
+ printf("\uc0\u25968 \u20516 \u12434 \u20837 \u21147 \u12375 \u12390 \u12367 \u12384 \u12373 \u12356 : ");\
129
+ // \uc0\u12304 \u21839 \u38988 \u28857 \u65306 scanf() \u12398 \u25147 \u12426 \u20516 \u12481 \u12455 \u12483 \u12463 \u19981 \u36275 \u12305 \
130
+ // scanf() \uc0\u12399 \u12289 \u27491 \u12375 \u12367 \u35501 \u12415 \u36796 \u12417 \u12383 \u38917 \u30446 \u25968 \u12434 \u36820 \u12375 \u12414 \u12377 \u12290 \
131
+ // \uc0\u12518 \u12540 \u12470 \u12540 \u12364 \u25968 \u20516 \u12434 \u20837 \u21147 \u12379 \u12378 \u12289 \u20363 \u12360 \u12400 \u25991 \u23383 \u21015 \u12434 \u20837 \u21147 \u12375 \u12383 \u22580 \u21512 \u12289 scanf\u12399 \u22833 \u25943 \u12375 number_input \u12398 \u20516 \u12364 \u26410 \u23450 \u32681 \u12395 \u12394 \u12427 \u21487 \u33021 \u24615 \u12364 \u12354 \u12426 \u12414 \u12377 \u12290 \
132
+ // \uc0\u26412 \u26469 \u12399 if (scanf("%d", &number_input) != 1) \u12398 \u12424 \u12358 \u12395 \u12481 \u12455 \u12483 \u12463 \u12377 \u12409 \u12365 \u12391 \u12377 \u12290 \
133
+ scanf("%d", &number_input);\
134
+ \
135
+ logMessage("\uc0\u12518 \u12540 \u12470 \u12540 \u20837 \u21147 \u12364 \u21463 \u12369 \u20184 \u12369 \u12425 \u12428 \u12414 \u12375 \u12383 \u12290 ");\
136
+ \
137
+ // toUpperCase\uc0\u38306 \u25968 \u12434 \u21628 \u12403 \u20986 \u12375 \u12289 \u22823 \u25991 \u23383 \u12395 \u22793 \u25563 \u12373 \u12428 \u12383 \u21517 \u21069 \u12434 \u21462 \u24471 \
138
+ char* upper_name = toUpperCase(name_buffer);\
139
+ if (upper_name == NULL) \{\
140
+ printf("\uc0\u21517 \u21069 \u12398 \u20966 \u29702 \u12395 \u22833 \u25943 \u12375 \u12414 \u12375 \u12383 \u12290 \\n");\
141
+ return 1; // \uc0\u12456 \u12521 \u12540 \u32066 \u20102 \
142
+ \}\
143
+ printf("\uc0\u22823 \u25991 \u23383 \u12398 \u21517 \u21069 : %s\\n", upper_name);\
144
+ \
145
+ // \uc0\u21361 \u38522 \u12394 \u35336 \u31639 \u12434 \u23455 \u34892 \
146
+ // global_counter \uc0\u12399 main \u38306 \u25968 \u38283 \u22987 \u26178 \u12399 0\u12289 logMessage\u12391 1\u12395 \u12394 \u12426 \u12289 \u12371 \u12398 \u26178 \u28857 \u12391 1\u12395 \u12394 \u12427 \
147
+ int calculation_result = performDangerousCalculation(number_input, global_counter);\
148
+ printf("\uc0\u35336 \u31639 \u32080 \u26524 : %d\\n", calculation_result);\
149
+ \
150
+ // \uc0\u12501 \u12449 \u12452 \u12523 \u12395 \u26360 \u12365 \u36796 \u12415 \u65288 \u12371 \u12371 \u12391 \u12418 \u12501 \u12449 \u12452 \u12523 \u12495 \u12531 \u12489 \u12523 \u12364 \u38281 \u12376 \u12425 \u12428 \u12414 \u12379 \u12435 \u65289 \
151
+ writeDataToFile("output.txt", upper_name, calculation_result);\
152
+ \
153
+ logMessage("\uc0\u12487 \u12540 \u12479 \u12364 \u12501 \u12449 \u12452 \u12523 \u12395 \u26360 \u12365 \u36796 \u12414 \u12428 \u12414 \u12375 \u12383 \u12290 ");\
154
+ \
155
+ // \uc0\u12304 \u21839 \u38988 \u28857 \u65306 \u12513 \u12514 \u12522 \u12522 \u12540 \u12463 \u12305 \
156
+ // toUpperCase() \uc0\u12391 \u21205 \u30340 \u12395 \u30906 \u20445 \u12375 \u12383 \u12513 \u12514 \u12522 (upper_name) \u12434 \u12371 \u12371 \u12391 free() \u12377 \u12427 \u24517 \u35201 \u12364 \u12354 \u12426 \u12414 \u12377 \u12364 \u12289 \u12373 \u12428 \u12390 \u12356 \u12414 \u12379 \u12435 \u12290 \
157
+ // free(upper_name); // \uc0\u12371 \u12428 \u12364 \u12394 \u12356 \u12392 \u12513 \u12514 \u12522 \u12522 \u12540 \u12463 \u12364 \u30330 \u29983 \u12375 \u12414 \u12377 \u12290 \
158
+ \
159
+ // \uc0\u12304 \u21839 \u38988 \u28857 \u65306 \u21029 \u12398 \u12513 \u12514 \u12522 \u12522 \u12540 \u12463 \u12305 \
160
+ // \uc0\u12371 \u12371 \u12391 \u12418 \u21205 \u30340 \u12395 \u12513 \u12514 \u12522 \u12434 \u30906 \u20445 \u12375 \u12390 \u12356 \u12414 \u12377 \u12364 \u12289 \u35299 \u25918 \u12373 \u12428 \u12390 \u12356 \u12414 \u12379 \u12435 \u12290 \
161
+ char* another_buffer = (char*)malloc(100);\
162
+ if (another_buffer == NULL) \{\
163
+ printf("\uc0\u21029 \u12398 \u12496 \u12483 \u12501 \u12449 \u12398 \u21106 \u12426 \u24403 \u12390 \u12395 \u22833 \u25943 \u12375 \u12414 \u12375 \u12383 \u12290 \\n");\
164
+ return 1;\
165
+ \}\
166
+ strcpy(another_buffer, "\uc0\u12371 \u12428 \u12399 \u21029 \u12398 \u21205 \u30340 \u12395 \u21106 \u12426 \u24403 \u12390 \u12425 \u12428 \u12383 \u12496 \u12483 \u12501 \u12449 \u12391 \u12377 \u12290 ");\
167
+ // free(another_buffer); // \uc0\u12371 \u12428 \u12418 \u35299 \u25918 \u12373 \u12428 \u12394 \u12356 \u12392 \u12513 \u12514 \u12522 \u12522 \u12540 \u12463 \u12364 \u30330 \u29983 \u12375 \u12414 \u12377 \u12290 \
168
+ \
169
+ printf("\uc0\u12503 \u12525 \u12464 \u12521 \u12512 \u12364 \u32066 \u20102 \u12375 \u12414 \u12375 \u12383 \u12290 \u12464 \u12525 \u12540 \u12496 \u12523 \u12459 \u12454 \u12531 \u12479 \u12540 : %d\\n", global_counter);\
170
+ \
171
+ return 0; // \uc0\u12503 \u12525 \u12464 \u12521 \u12512 \u12398 \u27491 \u24120 \u32066 \u20102 \
172
+ \}}
checklist/code_review_checklist.pdf ADDED
Binary file (76 kB). View file
 
checklist/coding_rule.pdf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:af74fe3006646cef4a5aaa7f841f96851106710dd9d9bf09f112c8e9ea657d0c
3
+ size 3745414